import re
from datetime import datetime
import pandas as pd
import plotly.express as px
import os
import sys
import tkinter as tk
from tkinter import filedialog

def parse_log_file(log_file):
    """解析日志文件并返回包含CPU和内存数据的DataFrame"""
    data = []
    current_time = None
    
    with open(log_file, 'r') as f:
        for line in f:
            line = line.strip()
            
            # 解析时间戳
            if line.startswith('20') and '-----------------------' in line:
                time_str = line.split('-----------------------')[0].strip()
                current_time = datetime.strptime(time_str, '%Y-%m-%d %H:%M:%S')
                continue
                
            # 跳过表头和空行
            if not line or line.startswith('USER') or line.startswith('Total'):
                continue
                
            # 解析进程信息
            cols = line.split()
            if len(cols) < 11:
                continue
                
            try:
                # 提取指标信息
                cpu_usage = float(cols[2])
                mem_usage = float(cols[3])
                
                # 提取节点名称
                command = ' '.join(cols[10:])
                node_match = re.search(r'__node:=(\w+)', command)
                if node_match:
                    node_name = node_match.group(1)
                else:
                    executable = cols[10].split('/')[-1]
                    node_name = re.sub(r'[_.-]', ' ', executable).title()
                
                data.append({
                    'timestamp': current_time,
                    'node': node_name,
                    'cpu': cpu_usage,
                    'mem': mem_usage
                })
            except Exception as e:
                print(f"解析错误: {line}\n错误信息: {str(e)}")

    return pd.DataFrame(data)

def create_interactive_plot(df, metric):
    """创建可交互的指标趋势图"""
    metric_label = 'CPU' if metric == 'cpu' else '内存'
    fig = px.line(df, 
                 x='timestamp', 
                 y=metric,
                 color='node',
                 labels={
                     metric: f'{metric_label}使用率 (%)',
                     'timestamp': '时间'
                 },
                 title=f'节点{metric_label}使用率趋势')
    
    # 添加时间控件
    fig.update_xaxes(
        rangeslider_visible=True,
        rangeselector=dict(
            buttons=list([
                dict(count=15, label="15秒", step="second", stepmode="backward"),
                dict(count=60, label="1分钟", step="second", stepmode="backward"),
                dict(step="all", label="全部")
            ])
        )
    )
    
    # 优化交互体验
    fig.update_layout(
        hovermode='x unified',
        height=600,
        legend=dict(
            orientation="h",
            yanchor="bottom",
            y=1.02,
            itemwidth=30
        ),
        margin=dict(b=20)
    )
    
    # 添加辅助线
    fig.update_traces(
        hovertemplate="<br>".join([
            "时间: %{x|%H:%M:%S}",
            f"{metric_label}使用率: %{{y}}%",
            "节点: %{fullData.name}"
        ])
    )
    
    return fig

def select_log_file():
    root = tk.Tk()
    root.withdraw()  # 隐藏主窗口
    file_path = filedialog.askopenfilename(
        title="选择日志文件",
        filetypes=[("Log files", "*.log"), ("All files", "*.*")]
    )
    root.destroy()
    return file_path

def main():
    log_file = select_log_file()
    if not log_file:
        print("未选择文件，程序退出")
        exit()
    df = parse_log_file(log_file)
    
    if not df.empty:
        print(f"解析成功 - 共 {len(df)} 条记录")
        print("正在生成可视化图表...")
        
        # 生成CPU图表
        cpu_fig = create_interactive_plot(df, 'cpu')
        cpu_fig.show()
        
        # 生成内存图表
        mem_fig = create_interactive_plot(df, 'mem')
        mem_fig.show()
    else:
        print("未解析到有效数据，请检查日志格式")

if __name__ == "__main__":
    main()